Contents: Newsletter Home | 1: Introduction | 2: Calculator | 3: Writing Code | 4: Appendix A
Before we begin writing code, we need to consider our design. How are we going to get from a skeleton User Interface to an operation program? We know some things from using real world calculators:
There are other unique features of a calculator's operation, but these are the main ones we will focus on for now.
To accomplish the first item we could use a string variable as a buffer. Each time a number is pressed we can add on to the end of the buffer and redisplay the value. This will require some string manipulation that we will explore a bit later.
In order to accomplish the second item is a bit trickier. We can not apply the selected operation immediately, as it actually applies to the current number, and the next number to be entered. This requires that we buffer the operation, and the current value until the next operation is selected. The logic looks something like this:
We will have to have some extra error checking to insure that a value is entered into the buffer between the pressing of operation keys. Also the pressing of equals will end the operation and complete the final combining of the values entered and the buffered operations.
As I mentioned above, the equals key will terminate the operations buffered and print the final result. It will clear the buffered operations as well. There is an additional function I want to integrate into the equals key: when the user presses equals, renders a result then presses a different operational key (+, -, x or division) the first value (step 1 above) will be taken from the display. This addresses the final item.
Let's get into the code. We already have a very nice skeleton around which to build our program. A great deal of the code has already been written. The real work of collecting user input and performing the arithmetic operations remain. I decided to code a single routine to handle all the operations, since they are little more complex than just adding a couple numbers together.
The key to this operation will be several variables that will handle the previous operation, current operation, previous value and current value. These variables need to be initialized at the beginning of the program. I have chosen the following variables for this:
buffer$ = "" currentop$ = "" lastop$ = "" eval = 0
buffer$ will be where we build the current value the user is keying into the calculator. currentop$ will be where we store the operation (+, -, x, division or equals) that the user just pressed. lastop$ will be where we store the operation (if any) the user requested last time. eval is a numeric variable in which we will hold the last value evaluated after an operation was completed.
Here is a rough bit of pseudo code that describes the operation of the routine to handle all calculator operations:
If the lastop is null then...
Else there is a lastop (which implies a last value in eval)
End if
Now display the result of the operation, but...
If the currentop is equals then
otherwise, this is just one step in a series of operations, so...
End if
goto main loop
As I indicated, it is a fair amont of complex code. The pseudo code should be enough to get most of you through the programming, as most of the logic is there, only the actual syntax is missing. The basic routine depends on a couple other sections of code. They are:
We also have a few other miscellaneous keys to handle, such "C" and "CE", not to mention the QUIT key. We will handle those later. Let us consider handling the input buffer.
Like I said earlier in our discussions, we would use a string variable as a buffer and collect the user input of numbers from the number keys. We do this by adding the key pressed onto the buffer string in the even handler for each key. The program skeleton that FreeForm created has handler sections of code for each key. Consider the "9":
[9buttonClick] 'Perform action for the button named 'btn9'
buffer$ = buffer$ + "9"
#main.tbx buffer$
wait
In this code I have added the string value "9" to what ever buffer held. Initially buffer$ was set to null. The next line simply displays the resulting value of buffer$ with out nine on the end in the textbox on the calculator form. Finally we wait. Every numeric key has such code under it, allowing the respective number to be added to the buffer.
The next item is the operation keys. Each of these will call the routine we laid out in pseudo code above. I called that routine "[operation]" late when it was coded. It is called (via a goto statement) by each of the operation keys. Consider the event handler for the addition operation:
[plusbuttonClick] 'Perform action for the button named 'btnplus'
'add buffer$ to eval
currentop$ = "+"
goto [operation]
The code for the common operation routine is below:
[operation]
if lastop$ = "" then
lastop$ = currentop$
eval = val(buffer$)
buffer$ = ""
wait
else
if lastop$ = "-" then
eval = eval - val(buffer$)
end if
if lastop$ = "+" then
eval = eval + val(buffer$)
end if
if lastop$ = "/" then
eval = eval / val(buffer$)
end if
if lastop$ = "*" then
eval = eval * val(buffer$)
end if
end if
if currentop$ = "=" then
lastop$ = ""
currentop$ = ""
buffer$ = ""
#main.tbx str$(eval)
eval = 0
else
lastop$ = currentop$
buffer$ = ""
#main.tbx str$(eval)
end if
wait
Compare this with the pseudo code to see how it all fits together.
The last pieces are the three miscellaneous keys. The quit key was the simplest - I just called the already cooded quite routine that FreeForm provided as a part of the skeleton code.
[qutibuttonClick] 'Perform action for the button named 'btnquit'
goto [main.quit]
The "C" key stands for clear all and start over. It results in a zero in the display, and clears all the buffers. The "CE" key is a little more complex in operation, as it clears the current value being put into the input buffer, resetting the display to the previous value and setting the input buffer to null. It retains any last operation stored in lastop though.
Here is the code to accomplish both of these items:
[cbuttonClick] 'Perform action for the button named 'btnc'
'C button clears everything and starts at the beginning
buffer$ = ""
lastop$ = ""
currentop$ = ""
eval = 0
#main.tbx "0"
wait
[cebuttonClick] 'Perform action for the button named 'btnce'
'Here we reset the buffer to the previous eval value
buffer$ = str$(eval)
if val(buffer$) = 0 then
buffer$ = ""
#main.tbx "0"
wait
else
#main.tbx buffer$
wait
end if
wait
This will result in a fairly complete calculator. It still is missing a few features that would make it an outstanding project. One of those was covered in my design ideas above, regarding the equal key operation.
We wanted the calculator to use the value displayed if the use pressed equals, then pressed another operator (indicating they wished to take the displayed value as starting value for the operation). This is really not too hard to do. If we detect an operator being pressed, but the input buffer is null, we need to get the contents of the display. We can do this with the "!contents?" textbox command. The Liberty Basic helpfile says the following about this command:
print #handle, "!contents? string$";
This command returns the entire text of the window. After this command is issued, the entire text is contained in the variable string$.
Note in the command that the variable (named string$) can be any valid string variable name. Note that it is enclosed in the quotes, which is unique for the operation in Liberty Basic. In the code below, which I used to accomplish the desired effect explained in the preceding section, I simply used the same "buffer$" I have used elsewhere in the program:
'sometimes people press an operation when a value is displayed after
'the equals key - buffer$ is null then - check for a value displayed
if buffer$ = "" then #main.tbx "!contents? buffer$"
Since the pressing of the equals key resets the contents of buffer$ as well as the lastop$ (meaning we quit tracking the previous operation) this can only happen when lastop$ is null.
One of the other issues we need to protect against is the troublesome divide by zero error. It is difficult to force this error, since you can not simply type a zero. I found that you can type a .0000 as the divider, which will cause the error. We need to trap this condition and protect against it. I did this by checking the value of buffer$ using the val function. This is what that code looks like:
'protect against divide by zero
if val(buffer$) = 0 then wait
The final operations routine after these changes looks like this:
[operation]
'this routine will execute any buffered operation
if lastop$ = "" then
lastop$ = currentop$
'sometimes people press an operation when a value is displayed after
'the equals key - buffer$ is null then - check for a value displayed
if buffer$ = "" then #main.tbx "!contents? buffer$"
eval = val(buffer$)
buffer$ = ""
wait
else
if lastop$ = "-" then
eval = eval - val(buffer$)
end if
if lastop$ = "+" then
eval = eval + val(buffer$)
end if
if lastop$ = "/" then
'protect against divide by zero
if val(buffer$) = 0 then wait
eval = eval / val(buffer$)
end if
if lastop$ = "*" then
eval = eval * val(buffer$)
end if
end if
if currentop$ = "=" then
lastop$ = ""
currentop$ = ""
buffer$ = ""
#main.tbx str$(eval)
eval = 0
else
lastop$ = currentop$
buffer$ = ""
#main.tbx str$(eval)
end if
wait
Another point about the calculator program regarding a technique I used throughout the program - if the buffer$ is known to be null (meaning it is equal to "") I do not put that value into the display; manually put a "0" into the display. I use the following code (which you will find throughout the program) to do this:
buffer$ = ""
#main.tbx "0"
The final item is a mater of polish. Most calculators I have used have the numeric display justified right, meaning the numbers are on the right side of the display. The textbox assumes normal text orientation, and is left justified. This is easily fixed if you are using version 4 of Liberty Basic.
Introduced with this new version is the command STYLEBITS. It is what I would call a more advanced command, which is easier understood with some "under-the-hood" windows experience. As a beginner's series, this knowledge is presumed to not be present, but it does not preclude us from tampering a bit.
What Stylebits does is apply (or remove) special window's controls modifiers to various window's controls. Most of the modifiers are not documented in the windows helpfile, as some of this basic "under-the-hood" knowledge is required to use some of them. There are a few more useful and easily implemented ones listed. Let's take a look at what the helpfile says about the command:
stylebits #handle, addBits, removeBits, addExtendedBits, removeExtendedBits
Description:
STYLEBITS allows you to change the style of a Liberty BASIC window or control. It accepts a handle and four parameters. When the window is opened it checks to see if there are style bits for the window or for any controls. If there is a STYLEBITS command it applies the remove bits first, then applies the add bits. In this way the control is created from the get-go with the desired style. The STYLEBITS command must be issued before the command to open the window.
This command works on all Liberty BASIC windows and controls, but since the texteditor is not a native Windows control you will only be able to do things like tweak it's border and perhaps a few other things.
Some common window and control styles are listed below. To find all possible style bits used to create controls in Windows, refer to API references online or in books for the functions to CreateWindow and CreateWindowEx.
#handle
This must be a handle of handle variable that refers to a control. See the code below for a demonstration.
addBits
This contains all style bits that should be added to the control. If there are more than one, they must be put together with the bitwise OR operator, like this: _ES_AUTOVSCROLL or _ES_MULTILINE
removeBits
This removes style bits from the control. To remove a border from a control, this value would be _WS_BORDER.
addExtendedBits
This adds bits to the extended style. Windows created with an extended style have extended style bits, like _WS_EX_CLIENTEDGE.
removeExtendedBits
This removes bits from the extended style. Windows created with an extended style have extended style bits, like _WS_EX_TOOLWINDOW .
WINDOW AND CONTROL STYLE CONSTANTS
window styles - some also work for controls:
_WS_BORDER Creates a window that has a thin-line border.
_WS_CAPTION Creates a window that has a title bar (includes the WS_BORDER style).
_WS_HSCROLL Creates a window that has a horizontal scroll bar.
_WS_MAXIMIZE Creates a window that is initially maximized.
_WS_MAXIMIZEBOX Creates a window that has a Maximize button.
_WS_MINIMIZE Creates a window that is initially minimized. Same as the WS_ICONIC style.
_WS_MINIMIZEBOX Creates a window that has a Minimize button.
_WS_VSCROLL Creates a window that has a vertical scroll bar.
button styles:
_BS_LEFT Left-justifies the text in the button rectangle.
_BS_RIGHT Right-justifies text in the button rectangle.
_BS_RIGHTBUTTON Positions a radio button's circle or a check box's square on the right side of the button rectangle.
editbox (textbox) styles:
_ES_CENTER Centers text in a multiline edit control.
_ES_PASSWORD Displays an asterisk (*) for each character typed into the edit control.
_ES_RIGHT Right-aligns text in a multiline edit control.
listbox styles:
_LBS_MULTICOLUMN Specifies a multicolumn list box that is scrolled horizontally.
_LBS_SORT Sorts strings in the list box alphabetically.
statictext styles:
_SS_CENTER Specifies a simple rectangle and centers the text in the rectangle.
_SS_RIGHT Specifies a simple rectangle and right-aligns the given text in the rectangle.
I especially like how easily this command can change a textbox. All we need to do is add a certain stylebit. We do not need to worry about any of the other more intricate functions of the command, like combining styles with the OR operator and the like. Under textbox styles in the helpfile we see _ES_RIGHT. Simply applying this to the textbox changes it, and gives the calculator a whole new look.
Notice that the _ES_RIGHT is a windows constant. In Liberty Basic all window's constants begin with an underscore. I found this stylebit change to be very easy to apply, as I was able to ignore the other options in the command, passing zeros instead.
If you have Liberty Basic version 4 or higher you can use this command; place it somewhere before the textbox command that creates the textbox GUI element. Here is the code fragment:
stylebits #main.tbx, _ES_RIGHT, 0, 0, 0
Note that if you are using version 3 of Liberty Basic, this effect can also be obtained, but it requires a much more advanced type of command called CALLDLL which gives programmers access to certain windows API (Application Programmer Interface) calls in windows.
This concludes the calculator program as developed in this installment of the newsletter. Here is my version running:

You can see the final program listing in Appendix A. Don't forget that I have also included the FreeForm file that creates the GUI elements in the newsletter archive.
This installment of the Beginners Series broke with tradition a bit, and we continue that with the challenge section again. First I am going to suggest a few enhancements to the calculator program. It would be great experience to work these through, adding to your skills as a Liberty Basic programmer. I will not be answering this challenge in the next installment though. I would encourage you to share your calculators online at the Liberty Basic conforums site though - visit it here:
Please consider some of these ideas to make your calculator a tool of great use:
As you can see from my simple list, the possibilities are endless. Enjoy yourself and see what you can create!
We have explored the world of FreeForm and really hope that you can add it to you list of Liberty Basic tools. It will help layout even the simplest forms for programs of nearly any type.
With the next installment of the Beginners Series we will be returning to our game roots. We will be developing a simple Pong Game (I hope, I have not fully written this one yet…). I do have a working mockup for you to study and play with. Try your hand at converting this simple animation demonstration program into a working game. Remember - have fun:
NOMAINWIN
WindowWidth = 515 : WindowHeight = 303
UpperLeftX = INT((DisplayWidth-WindowWidth)/2)
UpperLeftY = INT((DisplayHeight-WindowHeight)/2)
graphicbox #main.gfx, 10, 10, 480, 210
button #main.go, "Go!",[go],UL, 385, 230, 105, 25
Open "Window Title" for Window as #main
#main "trapclose [quit]"
#main.gfx "down; fill White; flush"
#main "font ms_sans_serif 10"
[loop]
Wait
[quit]
close #main
END
[go]
#main.gfx "color white"
#main.gfx "backcolor red"
#main.gfx "up; goto 20 80; down; circlefilled 8"
for x = 20 to 440 step 2
#main.gfx "backcolor white"
#main.gfx "up; goto ";x;" 80; down; circlefilled 8"
#main.gfx "backcolor red"
#main.gfx "up; goto ";x+2;" 80; down; circlefilled 8"
for y = 1 to 750 : next y
next x
wait